﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using LinqToAmazonSL;

namespace SilverlightApplication.UIControls.Carousel
{
    public class CarouselItem : Grid
    {
        #region Members

        Plane3D pBackground;
        Plane3D pImage;
        AmazonItem data;
        BitmapImage image;
        BitmapImage bgImage;

        static CarouselItemBackup lastSavedState = null;

        public bool MouseLeft = true;
        public bool EnlargeCompleted = true;

        public int ResultNumber = -1;

        private bool rollHides = false;
        private bool pitchHides = false;
        private bool yawHides = false;
        
        #endregion

        #region Events

        public delegate void CarouselItemClick(CarouselItem sender);
        public event CarouselItemClick carouselItemClick;
        public delegate void CarouselItemEnter(CarouselItem sender);
        public event CarouselItemEnter carouselItemEnter;
        public delegate void CarouselItemLeave(CarouselItem sender);
        public event CarouselItemLeave carouselItemLeave;

        #endregion

        #region Dependency Properties

        public static readonly DependencyProperty XProperty;
        public static readonly DependencyProperty YProperty;
        public static readonly DependencyProperty ScaleProperty;
        public static readonly DependencyProperty PitchProperty;
        public static readonly DependencyProperty YawProperty;
        public static readonly DependencyProperty RollProperty;

        #endregion

        #region Properties

        public double X
        {
            get { return (double)GetValue(XProperty); }
            set { SetValue(XProperty, value); }
        }

        public double Y
        {
            get { return (double)GetValue(YProperty); }
            set { SetValue(YProperty, value); }
        }

        public double Scale
        {
            get { return (double)GetValue(ScaleProperty); }
            set { SetValue(ScaleProperty, value); }
        }

        public double Pitch
        {
            get { return (double)GetValue(PitchProperty); }
            set { SetValue(PitchProperty, value); }
        }

        public double Yaw
        {
            get { return (double)GetValue(YawProperty); }
            set { SetValue(YawProperty, value); }
        }

        public double Roll
        {
            get { return (double)GetValue(RollProperty); }
            set { SetValue(RollProperty, value); }
        }

        public AmazonItem Data
        {
            get { return data; }
            set
            {
                data = value;

                if (value != null)
                {
                    if (value.GetType() == typeof(AmazonBook))
                    {
                        AmazonBook ab = value as AmazonBook;
                        if (ab.Image != null && !ab.Image.URL.EndsWith(".gif"))
                        {
                            image.UriSource = new Uri(ab.Image.URL);
                            pImage.AspectRatio = (double)(ab.Image.Width.Value / ab.Image.Height.Value);
                            pBackground.AspectRatio = (double)(ab.Image.Width.Value / ab.Image.Height.Value);
                        }
                        else
                        {
                            ab.Image = null;
                            image.UriSource = new Uri("/SilverlightApplication;component/UIControls/Carousel/Resources/book_no_image.jpg", UriKind.Relative);
                            pImage.AspectRatio = 4 / 3.0f;
                            pBackground.AspectRatio = 4 / 3.0f;
                        }
                    }
                    else
                    {
                        AmazonDVD ab = value as AmazonDVD;
                        if (ab.Image != null && !ab.Image.URL.EndsWith(".gif"))
                        {
                            image.UriSource = new Uri(ab.Image.URL);
                            pImage.AspectRatio = (double)(ab.Image.Width.Value / ab.Image.Height.Value);
                            pBackground.AspectRatio = (double)(ab.Image.Width.Value / ab.Image.Height.Value);
                        }
                        else
                        {
                            ab.Image = null;
                            image.UriSource = new Uri("/SilverlightApplication;component/UIControls/Carousel/Resources/dvd_no_image.jpg", UriKind.Relative);
                            pImage.AspectRatio = 4 / 3.0f;
                            pBackground.AspectRatio = 4 / 3.0f;
                        }
                    }
                }
                else
                {
                    image.UriSource = new Uri("/SilverlightApplication;component/UIControls/Carousel/Resources/bg.jpg", UriKind.Relative);
                }
            }
        }

        #endregion

        #region Constructors

        static CarouselItem()
        {
            XProperty = DependencyProperty.Register("X",
                                                    typeof(double),
                                                    typeof(CarouselItem),
                                                    new PropertyMetadata(OnXChanged));

            YProperty = DependencyProperty.Register("Y",
                                                    typeof(double),
                                                    typeof(CarouselItem),
                                                    new PropertyMetadata(OnYChanged));

            ScaleProperty = DependencyProperty.Register("Scale",
                                                    typeof(double),
                                                    typeof(CarouselItem),
                                                    new PropertyMetadata(OnScaleChanged));

            PitchProperty = DependencyProperty.Register("Pitch",
                                                    typeof(double),
                                                    typeof(CarouselItem),
                                                    new PropertyMetadata(OnPitchChanged));

            YawProperty = DependencyProperty.Register("Yaw",
                                                    typeof(double),
                                                    typeof(CarouselItem),
                                                    new PropertyMetadata(OnYawChanged));

            RollProperty = DependencyProperty.Register("Roll",
                                                    typeof(double),
                                                    typeof(CarouselItem),
                                                    new PropertyMetadata(OnRollChanged));
        }

        public CarouselItem()
        {
            pBackground = new Plane3D(1) { Scale = 1.02 };
            bgImage = new BitmapImage(new Uri("/SilverlightApplication;component/UIControls/Carousel/Resources/bg.jpg", UriKind.Relative));
            pBackground.setImage(bgImage);

            pImage = new Plane3D() { Scale = 1 };
            image = new BitmapImage(new Uri("/SilverlightApplication;component/UIControls/Carousel/Resources/bg.jpg", UriKind.Relative));
            pImage.setImage(image);

            this.Children.Add(pBackground);
            this.Children.Add(pImage);

            pImage.planeClick += new Plane3D.PlaneClick(pImage_planeClick);
            pImage.planeEnter += new Plane3D.PlaneEnter(pImage_planeEnter);
            pImage.planeLeave += new Plane3D.PlaneLeave(pImage_planeLeave);
        }

        void pImage_planeLeave()
        {
            if (carouselItemLeave != null)
                carouselItemLeave(this);
        }

        void pImage_planeEnter()
        {
            if (carouselItemEnter != null)
                carouselItemEnter(this);
        }

        void pImage_planeClick()
        {
            if (carouselItemClick != null)
                carouselItemClick(this);
        }

        #endregion

        #region Implementation

        private static void OnXChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            CarouselItem c = (CarouselItem)obj;

            c.pBackground.X = (double)c.GetValue(XProperty);
            c.pImage.X = (double)c.GetValue(XProperty);
        }

        private static void OnYChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            CarouselItem c = (CarouselItem)obj;

            c.pBackground.Y = (double)c.GetValue(YProperty);
            c.pImage.Y = (double)c.GetValue(YProperty);
        }

        private static void OnScaleChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            CarouselItem c = (CarouselItem)obj;

            c.pBackground.Scale = (double)c.GetValue(ScaleProperty) * 1.02;
            c.pImage.Scale = (double)c.GetValue(ScaleProperty);
        }

        private static void OnPitchChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            CarouselItem c = (CarouselItem)obj;
            double pitch = (double)c.GetValue(PitchProperty);

            pitch = Mod(pitch, 360);
            c.pBackground.Pitch = pitch;
            c.pImage.Pitch = pitch;

            if (pitch > 90 && pitch < 270)
                c.pitchHides = true;
            else
                c.pitchHides = false;

            c.checkImageVisibility();
        }

        private static void OnYawChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            CarouselItem c = (CarouselItem)obj;
            double yaw = (double)c.GetValue(YawProperty);

            yaw = Mod(yaw, 360);
            c.pBackground.Yaw = yaw;
            c.pImage.Yaw = yaw;

            if (yaw > 90 && yaw < 270)
                c.yawHides = true;
            else
                c.yawHides = false;

            c.checkImageVisibility();
        }

        private static void OnRollChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            CarouselItem c = (CarouselItem)obj;
            double roll = (double)c.GetValue(RollProperty);

            roll = Mod(roll, 360);
            c.pBackground.Roll = roll;
            c.pImage.Roll = roll;

           
        }

        #endregion

        void checkImageVisibility()
        {
            if (pitchHides || rollHides || yawHides)
            {
                pImage.Opacity = 0;
            }
            else
            {
                pImage.Opacity = 1;
            }
        }

        #region Public Methods

        public void setImage(BitmapImage b)
        {
            pImage.setImage(b);
        }

        public static void saveState(CarouselItem p)
        {
            if (lastSavedState == null)
            {
                lastSavedState = new CarouselItemBackup()
                {
                    X = p.X,
                    Y = p.Y,
                    Scale = p.Scale,
                    Pitch = p.Pitch,
                    Yaw = p.Yaw,
                    Roll = p.Roll,
                    Opacity = p.Opacity
                };
            }
        }

        public static void restoreState(CarouselItem p)
        {
            if (lastSavedState != null)
            {
                p.X = lastSavedState.X;
                p.Y = lastSavedState.Y;
                p.Scale = lastSavedState.Scale;
                p.Pitch = lastSavedState.Pitch;
                p.Yaw = lastSavedState.Yaw;
                p.Roll = lastSavedState.Roll;
                p.Opacity = lastSavedState.Opacity;
            }

            lastSavedState = null;
        }

        #endregion

        static double Mod(double a, double b)
        {
            while (a < 0)
                a += b;
            while (a >= b)
                a -= b;

            return a;
        }
    }

    public class CarouselItemBackup
    {
        public double X, Y, Scale, Pitch, Yaw, Roll, Opacity;
    }
}
